package com.polaris.live.widget.bubble

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.LifecycleCoroutineScope
import androidx.lifecycle.lifecycleScope
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.util.ViewUtils
import com.polaris.live.manager.DownFileManager
import com.polaris.live.utils.file.FileUtils
import com.polaris.live.utils.image.ImageUtils
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import zlc.season.rxdownload4.download
import zlc.season.rxdownload4.task.Task
import java.io.File
import java.util.concurrent.ConcurrentHashMap

/**
 * DownLoadFileUtil 下载资源帮助类
 * @author Created by 天晴 on 2024/1/30 12:00
 * @since 1.0.0
 **/
object DownLoadFileUtil {

    /**
     * 正在下载的文件列表
     */
    private val downList = ConcurrentHashMap<String, Deferred<String?>>()

    /**
     * 网络下载.9图
     */
    suspend fun getNineBitMap(url: String): Bitmap? = coroutineScope {
        val pathDir = FileUtils.getBubbleFile()
        val name = url.substringAfterLast("/")
        val pa = url.substringBeforeLast("/")
        var filePath = FileUtils.getFilePath("$pathDir/$pa", name)
        if (!File(filePath).exists()) {
            filePath = downloadFile("$pathDir/$pa", name, url).await() ?: return@coroutineScope null
        }
        return@coroutineScope BitmapFactory.decodeFile(filePath)
    }

    /**
     * 获取Pag地址
     */
    suspend fun getPagPath(url: String): String? = coroutineScope {
        val pathDir = FileUtils.getPagFile()
        val name = url.substringAfterLast("/")
        val pa = url.substringBeforeLast("/")
        var filePath = FileUtils.getFilePath("$pathDir/$pa", name)
        if (!File(filePath).exists()) {
            filePath = downloadFile("$pathDir/$pa", name, url).await() ?: return@coroutineScope null
        }
        return@coroutineScope filePath
    }

    /**
     * 获取音乐地址
     */
    suspend fun getAudioPath(url: String): String? = coroutineScope {
        val pathDir = FileUtils.getAudioFile()
        val name = url.substringAfterLast("/")
        val pa = url.substringBeforeLast("/")
        var filePath = FileUtils.getFilePath("$pathDir/$pa", name)
        if (!File(filePath).exists()) {
            filePath = downloadFile("$pathDir/$pa", name, url).await() ?: return@coroutineScope null
        }
        return@coroutineScope filePath
    }

    /**
     * 下载文件  限制一个链接只能一次下载其他等待
     */
    private fun downloadFile(
        savePath: String,
        fileName: String,
        url: String,
    ): Deferred<String?> {
        return downList.getOrPut(url) {
            val deferred = CompletableDeferred<String?>()
            downloadReality(savePath, fileName, url, deferred)
            deferred.invokeOnCompletion {
                downList.remove(url, deferred)
            }
            deferred
        }
    }

    /**
     * 下载文件并保存到本地
     */
    private fun downloadReality(
        savePath: String,
        fileName: String,
        url: String,
        deferred: CompletableDeferred<String?>,
    ) {
        Task(
            ImageUtils.imgPath(url),
            saveName = fileName,
            savePath = savePath
        ).download()
            .subscribe({}, {
                deferred.complete(null)
            }, {
                deferred.complete("$savePath/$fileName")
            }).let {

            }
    }

    /**
     * 下载pag和pag音效
     *
     * pagOut 原地址  本地地址
     * audioOut 原地址  本地地址
     */
    fun downPagAndAudio(
        lifecycleScope: LifecycleCoroutineScope?,
        pagPath: String,
        audioPath: String,
        loadCallback: ((pagOut: Pair<String, String?>, audioOut: Pair<String, String?>) -> Unit)? = null,
    ) {
        var scope = lifecycleScope
        if (lifecycleScope == null) {
            val activity = ViewUtils.getAliveTopActivity()
            if (activity is AppCompatActivity) {
                scope = activity.lifecycleScope
            }
        }
        if (scope == null) {
            loadCallback?.invoke(pagPath to null, audioPath to null)
            return
        }

        scope.launch(CoroutineScopeManager.ioDispatcher) {
            val pagDeferred = async {
                getPagPath(pagPath)
            }
            val audioDeferred = async {
                getAudioPath(audioPath)
            }
            val carPath = pagDeferred.await()
            val carSoundPath = audioDeferred.await()
            withContext(CoroutineScopeManager.mainDispatcher) {
                loadCallback?.invoke(pagPath to carPath, audioPath to carSoundPath)
            }
        }
    }

    //下载
    fun loadPag(
        lifecycleScope: LifecycleCoroutineScope,
        pagPath: String,
        loadCallback: ((pagPath: String, localPath: String) -> Unit)? = null,
    ) {
        val path =
            FileUtils.getFilePath(FileUtils.getPagFile(), pagPath)
        //如果pag已经存在代表下过了直接回调
        if (File(path).exists()) {
            loadCallback?.invoke(pagPath, path)
            return
        }
        lifecycleScope.launch(CoroutineScopeManager.ioDispatcher) {
            val loadFileCallback = DownFileManager.loadFileCallback(
                FileUtils.getPagFile(),
                pagPath
            )
            withContext(CoroutineScopeManager.mainDispatcher) {

                val loadPath = loadFileCallback?.second?.let {
                    FileUtils.getFilePath(FileUtils.getPagFile(), it)
                }
                loadPath?.let {
                    loadCallback?.invoke(pagPath, loadPath)
                }

            }
        }
    }

    //下载Pag全局  直到下载完毕
    fun loadPag(
        pagPath: String?,
        loadCallback: ((pagPath: String, localPath: String) -> Unit)? = null,
    ) {
        if (pagPath == null) return

        val path = FileUtils.getFilePath(FileUtils.getPagFile(), pagPath)
        //如果pag已经存在代表下过了直接回调
        if (File(path).exists()) {
            loadCallback?.invoke(pagPath, path)
            return
        }
        CoroutineScopeManager.ioScope.launch {
            val loadFileCallback = getPagPath(pagPath)
            withContext(CoroutineScopeManager.mainDispatcher) {
                loadFileCallback?.let {
                    loadCallback?.invoke(pagPath, loadFileCallback)
                }
            }
        }
    }
}